package com.pt25.base.dep.redis;

import com.pt25.base.dep.redis.dw.RedisDwData;
import com.pt25.base.dep.redis.dw.RedisDwDataBase;
import com.pt25.base.dep.redis.dw.RedisDwMapData;
import com.pt25.base.dep.redis.dw.RedisDwZSetData;
import com.pt25.base.util.CollectionUtil;
import com.pt25.base.util.ExecutorUtil;
import jakarta.annotation.Resource;
import org.redisson.api.RBatch;
import org.redisson.client.codec.StringCodec;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.List;


/**
 * redis双写service
 * <p>
 * 通过双写写入redis的数据可以方便后期多数据中心搭建和数据的迁移
 */
@Service
public class RedisDoubleWriteService {

    @Resource
    private RedisService redisService;

    /**
     * redis双写接口，主要方便后期多中心和数据迁移，建议所有redis数据写入通过双写接口
     */
    public void doubleWrite(RedisDwData redisDwData) {
        redisDwData.getRedisNames().forEach(redisName -> {
            ExecutorUtil.getExecutor(redisName).execute(() -> {
                RBatch batch = redisService.getRedissonClient(redisName).createBatch();
                saveStrData(batch, redisDwData.getStrDataList());
                saveMapData(batch, redisDwData.getMapDataList());
                saveSetData(batch, redisDwData.getSetDataList());
                saveListData(batch, redisDwData.getListDataList());
                saveZSetData(batch, redisDwData.getZsetDataList());
                batch.execute();
            });
        });
    }

    private void saveStrData(RBatch batch, List<RedisDwDataBase> redisDwDataBaseList) {
        if (CollectionUtil.isNotEmpty(redisDwDataBaseList)) {
            redisDwDataBaseList.forEach(redisDwDataBase -> {
                if (redisDwDataBase.getExpiredSeconds() > 0 || redisDwDataBase.getExpiredSeconds() == -1)
                    batch.getBucket(redisDwDataBase.getCacheKey(), new StringCodec()).setAsync(redisDwDataBase.getCacheData());
                if (redisDwDataBase.getExpiredSeconds() >= 0)
                    batch.getBucket(redisDwDataBase.getCacheKey(), new StringCodec()).expireAsync(Duration.ofSeconds(redisDwDataBase.getExpiredSeconds()));
            });
        }
    }

    private void saveMapData(RBatch batch, List<RedisDwMapData> redisDwDataBaseList) {
        if (CollectionUtil.isNotEmpty(redisDwDataBaseList)) {
            redisDwDataBaseList.forEach(redisDwDataBase -> {
                if (redisDwDataBase.getExpiredSeconds() > 0 || redisDwDataBase.getExpiredSeconds() == -1)
                    batch.getMap(redisDwDataBase.getCacheKey(), new StringCodec()).putAsync(redisDwDataBase.getMapKey(), redisDwDataBase.getCacheData());
                if (redisDwDataBase.getExpiredSeconds() >= 0)
                    batch.getMap(redisDwDataBase.getCacheKey(), new StringCodec()).expireAsync(Duration.ofSeconds(redisDwDataBase.getExpiredSeconds()));
            });
        }
    }

    private void saveSetData(RBatch batch, List<RedisDwDataBase> redisDwDataBaseList) {
        if (CollectionUtil.isNotEmpty(redisDwDataBaseList)) {
            redisDwDataBaseList.forEach(redisDwDataBase -> {
                if (redisDwDataBase.getExpiredSeconds() > 0 || redisDwDataBase.getExpiredSeconds() == -1)
                    batch.getSet(redisDwDataBase.getCacheKey(), new StringCodec()).addAsync(redisDwDataBase.getCacheData());
                if (redisDwDataBase.getExpiredSeconds() >= 0)
                    batch.getSet(redisDwDataBase.getCacheKey(), new StringCodec()).expireAsync(Duration.ofSeconds(redisDwDataBase.getExpiredSeconds()));
            });
        }
    }

    private void saveListData(RBatch batch, List<RedisDwDataBase> redisDwDataBaseList) {
        if (CollectionUtil.isNotEmpty(redisDwDataBaseList)) {
            redisDwDataBaseList.forEach(redisDwDataBase -> {
                if (redisDwDataBase.getExpiredSeconds() > 0 || redisDwDataBase.getExpiredSeconds() == -1)
                    batch.getList(redisDwDataBase.getCacheKey(), new StringCodec()).addAsync(redisDwDataBase.getCacheData());
                if (redisDwDataBase.getExpiredSeconds() >= 0)
                    batch.getList(redisDwDataBase.getCacheKey(), new StringCodec()).expireAsync(Duration.ofSeconds(redisDwDataBase.getExpiredSeconds()));
            });
        }
    }

    private void saveZSetData(RBatch batch, List<RedisDwZSetData> redisDwDataBaseList) {
        if (CollectionUtil.isNotEmpty(redisDwDataBaseList)) {
            redisDwDataBaseList.forEach(redisDwDataBase -> {
                if (redisDwDataBase.getExpiredSeconds() > 0 || redisDwDataBase.getExpiredSeconds() == -1)
                    batch.getScoredSortedSet(redisDwDataBase.getCacheKey(), new StringCodec()).addAsync(redisDwDataBase.getScore(), redisDwDataBase.getCacheData());
                if (redisDwDataBase.getRemainSize() > 0)
                    batch.getScoredSortedSet(redisDwDataBase.getCacheKey(), new StringCodec()).removeRangeByRankAsync(redisDwDataBase.getRemainSize(), -1);
                if (redisDwDataBase.getExpiredSeconds() >= 0)
                    batch.getScoredSortedSet(redisDwDataBase.getCacheKey(), new StringCodec()).expireAsync(Duration.ofSeconds(redisDwDataBase.getExpiredSeconds()));
            });
        }
    }
}
